本文在mpvue提供的默认项目模板的基础上,对webpack构建过程进行了优化,使其更加符合大型的小程序项目。
1. 清理废弃页面
随着产品的快速迭代,项目里的部分页面会逐渐下线。为了避免下线的页面突然又要重新上线,开发同学一般会把下线页面的代码保留,仅仅在app.json
里移除掉相应的页面。
但细心的同学可能会发现,尽管已经在app.json
里移除了相应页面的路径,在编译出来的dist文件夹仍然能发现已下线页面的身影,这是为什么呢?
答案就在webpack.base.config.js
里的这段代码里:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function resolve (dir) { return path.join(__dirname, '..', dir) } function getEntry (rootSrc) { var map = {}; glob.sync(rootSrc + '/pages/**/main.js') .forEach(file => { var key = relative(rootSrc, file).replace('.js', ''); map[key] = file; }) return map; } const appEntry = { app: resolve('./src/main.js') } const pagesEntry = getEntry(resolve('./src'), 'pages/**/main.js') const entry = Object.assign({}, appEntry, pagesEntry)
|
可以看到mpvue的做法是去遍历src/pages
目录下的所有main.js
文件, 将他们所在的路径作为webapck的entry,参与编译。因此即使的已经从app.json
里移除了下线页面,只要他们的main.js
还在,就还会被编译。
那么最简单的解决方法显而易见——将下线页面的main.js
改名,例如改成main-old.js
就不会被编译了。
可是手动改文件名来下线页面实在是太蠢了,有没有更自动一点的方法呢?答案是肯定的。
我们能看到,其实我们需要编译哪些页面,全都已经写在app.json
里了。(什么?你说你app.json
里也没有删掉下线页面?那你可以被拖出去打了)
app.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| { "pages": [ "pages/index/home/main", // ... ], "subpackages": [ { "root": "pages/sub", "pages": [ "card/main" ] } ] // ... }
|
那么其实我们只要根据app.json
里的页面来改写getEntry
方法就好了,改写完后的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| function getEntry(rootSrc, globPattern) { const appJson = require('../src/app.json') const appJsonPages = appJson.pages.slice() if (appJson.subpackages) { appJson.subpackages.forEach(package => { package.pages.forEach(subPage => appJsonPages.push(`${package.root}/${subPage}`)) }) } var map = {}; glob.sync(globPattern) .forEach(file => { var key = relative(rootSrc, file).replace('.js', ''); const keyWithSep = key.split(path.sep).join('/') if (appJsonPages.includes(keyWithSep)) { map[key] = file; } else { console.log(`[:exclamation:注意:exclamation:] 页面 ${key} 不在app.json中,没有被编译`) } }) return map; }
|
这样我们就只需要对app.json
进行删减,就能够轻松下线页面啦。
2. 处理分包的公共代码
小程序其实可以看作是一个多页应用,在启动时只会下载主包的页面及公共代码,当跳转到分包页面时,才会开始下载分包页面的代码。
更多分包的介绍详见官方文档:分包加载 | 微信开放文档
在某次编译的时候,微信开发者工具突然提示common/vendor.js
文件体积大于500KB, 不会被执行ES6转ES5。令人奇怪的是最近一段时间主包代码并没有什么大改动,主要都是在分包新增页面,为什么公共的common/vendor.js
体积会变大呢?
使用webpack-bundle-analyzer
查看了一下common/vendor.js
的构成,意外的发现里面居然包含了不少分包的公共代码!本来使用分包,就是为了减小主包体积,加快启动速度。结果现在主包里却包含了主包里不会执行的分包代码,显然是不符合我们预期的。
老规矩,直接去看webpack相应的配置:
查阅资料得知,common/vendor.js
是webpack插件CommonsChunkPlugin
用来提取公共代码的(吐槽一句:该插件已经在webpack4中被移除,可惜没人维护的mpvue一直没支持webpack4)。
而默认模板里commonChunksPlugin
是这么写的:
1 2 3 4 5 6 7 8 9 10 11 12 13
| new webpack.optimize.CommonsChunkPlugin({ name: 'common/vendor', minChunks: function (module, count) { return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf('node_modules') >= 0 ) || count > 1 } }),
|
上面的代码会将引用到的npm包或者引用次数>1的代码提取到common/vendor.js
里,这也就是为什么common/vendor.js
会包含分包代码的原因了——因为分包里存在引用次数>1的代码。
我们的改造方向其实也很清楚:只要将分包的公共代码,放回分包里面就好了。
查询CommonsChunkPlugin的文档可知,该插件有一个可选参数chunks,用来指定提取公共代码的chunks范围。
什么是chunk呢? 简单来说就是webpack里通过entry解析出来的一块相互依赖的资源,在小程序的场景下,可以简单将chunk看作小程序的页面。
如果你对上文的getEntry
方法有印象,就能发现其实entry这个对象里的key就是这个页面的chunk name。如果你没有魔改过相关代码,那么页面的chunk name同时也等于它的path。因此,我们只要根据分包的构成,新增多个CommonsChunkPlugin
,将他们的chunks字段填上该分包的页面即可。
改良后的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| const appJson = require('../src/app.json') const subpackages = {} if (appJson.subpackages) { appJson.subpackages.forEach(package => { subpackages[package.root] = [] package.pages.forEach(subPage => subpackages[package.root].push(path.join(package.root, subPage))) }) } const subPackageCommonChunks = Object.keys(subpackages).map(sub => new webpack.optimize.CommonsChunkPlugin({ name: path.join(sub, 'common'), chunks: subpackages[sub], minChunks: 2, }) ) module.exports = merge(baseWebpackConfig, { plugins: [ ...subPackageCommonChunks, new webpack.optimize.CommonsChunkPlugin({ name: 'common/vendor', minChunks: function (module, count) { return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf('node_modules') >= 0 ) || count > 1 } }) ] })
|
这时候再用webpack-bundle-analyzer
看一下bundle构成,就会发现common/vendor.js
里已经基本没什么分包的代码啦~
小结
以上就是在使用mpvue开发过程过中对webpack构建过程作出的优化,分享给同样在使用mpvue做开发的小伙伴们。
其实构建优化这里可以做的还有很多,例如公共样式的提取、将仅在分包使用的npm包打包进分包以及app.json新增不存在的路径时自动创建目录等,如果你有好的想法,欢迎一起来交流学习~
最后说一句,如果你是准备开始一个新项目,请出门左转直接用原生语法写小程序吧,框架的坑实在太深了;(